﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.IO;
using System.Xml.Serialization;
using System.Xml;
using Microsoft.TeamFoundation.WorkItemTracking.Client;


namespace SnapShot
{
    public partial class frmSnapShot : Form
    {
        private SnapShot Configuracao;
        
        private string ArquivoConfig = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\SnapShot\Config.xml";

        #region fields
        public static int MOD_ALT = 0x1;
        public static int MOD_CONTROL = 0x2;
        public static int MOD_SHIFT = 0x4;
        public static int MOD_WIN = 0x8;
        public static int WM_HOTKEY = 0x312;
        #endregion

        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);

        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hWnd, int id);

        private static int keyId = 0;
        public static void RegisterHotKey(Form f, Keys key)
        {            
            int modifiers = 0;

            if ((key & Keys.Alt) == Keys.Alt)
                modifiers = modifiers | MOD_ALT;

            if ((key & Keys.Control) == Keys.Control)
                modifiers = modifiers | MOD_CONTROL;

            if ((key & Keys.Shift) == Keys.Shift)
                modifiers = modifiers | MOD_SHIFT;

            Keys k = key & ~Keys.Control & ~Keys.Shift & ~Keys.Alt;

            Func ff = delegate()
                {
                    //keyId = f.GetHashCode(); 
                    keyId++;
                    RegisterHotKey((IntPtr)f.Handle, keyId, modifiers, (int)k);
                };

            f.Invoke(ff);
        }

        private delegate void Func();

        public static void UnregisterHotKey(Form f)
        {
            try
            {
                Func ff = delegate()
                {
                    UnregisterHotKey(f.Handle, keyId);
                };

                f.Invoke(ff);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            Keys k = Keys.PrintScreen | Keys.Control;
            //Keys k = Keys.Back | Keys.Control;
            RegisterHotKey(this, k);

            Keys c = Keys.PrintScreen | Keys.Control | Keys.Shift;
            RegisterHotKey(this, c);

            Keys pu = Keys.PageUp | Keys.Alt;
            RegisterHotKey(this, pu);

            Keys pd = Keys.PageDown | Keys.Alt;
            RegisterHotKey(this, pd);
        }

        public frmSnapShot()
        {
            InitializeComponent();
        }

        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
            // 2883586 C P
            // 2883590 C S P
            // 2162689 A PU
            // 2228225 A PD
            
            if (m.Msg == WM_HOTKEY)
            {
                //VK_SNAPSHOT = 0x2C
                switch (m.LParam.ToInt32())
                {
                    case 2883586: // Keys.PrintScreen | Keys.Control;                        
                        this.PrintScreen();
                        break;
                    case 2883590:
                        this.Show();
                        this.WindowState = FormWindowState.Normal;
                        break;
                    case 2162689:
                        btnAvançar_Click(null, null);
                        break;
                    case 2228225:
                        btnVoltar_Click(null, null);
                        break;
                    default:
                        break;
                }
            }           
            
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            UnregisterHotKey(this);
        }

        private void PrintScreen()
        {   
            Configuracao.NumeroFoto++;            

            nIcon.ShowBalloonTip(1000, "Foto de Caso de Teste", String.Format("Caso: {0:D3} - Teste: {1:D3}.", Configuracao.NumeroCaso, Configuracao.NumeroFoto), ToolTipIcon.Info);

            Image printscreen = CaptureAndSave();
            
            Screen sc = Screen.PrimaryScreen;           

            Graphics graphics = Graphics.FromImage(printscreen);  

            graphics.FillRectangle(new SolidBrush(Color.Black), sc.Bounds.Width / 2, 0, sc.Bounds.Width / 2, 60);

            graphics.DrawString(DateTime.Now.ToString() + " - " + Environment.UserName, new Font(new FontFamily("Tahoma"), 16), new SolidBrush(Color.Yellow), sc.Bounds.Width / 2, 0);
            graphics.DrawString(String.Format("Caso: {0:D3} -  Teste: {1:D3}", Configuracao.NumeroCaso, Configuracao.NumeroFoto), new Font(new FontFamily("Tahoma"), 16), new SolidBrush(Color.Yellow), sc.Bounds.Width / 2, 30);
            
            string sFile = String.Format(@"{0}\[{5}] {1} - C{2:D3}T{3:D3} - {4}.gif", Configuracao.Diretorio, Configuracao.Prefixo, Configuracao.NumeroCaso, Configuracao.NumeroFoto, Environment.UserName, Configuracao.TFSConfig.WorkItem);

            Size nSize = new Size(sc.Bounds.Width, sc.Bounds.Height);

            Image imgPequena = new Bitmap(nSize.Width, nSize.Height, PixelFormat.Format16bppRgb555);
            
            using (Graphics g = Graphics.FromImage(imgPequena))
            {
                g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
                g.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality;

                //System.Drawing.Imaging.ImageCodecInfo codec = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()[1];
                //System.Drawing.Imaging.EncoderParameters eParams = new System.Drawing.Imaging.EncoderParameters(2);

                //eParams.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 100L);
                //eParams.Param[1] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.ColorDepth, 4L);

                g.DrawImage(printscreen, new Rectangle(0, 0, imgPequena.Width, imgPequena.Height));
                
                //printscreen.Save(sFile, ImageFormat.Jpeg);
                imgPequena.Save(sFile, ImageFormat.Gif);
            }

            if (Configuracao.TFSConfig.UsarTFS && Configuracao.TFSConfig.WorkItem != null && Configuracao.TFSConfig.WorkItem.Value > 0)
            {
                WorkItem wi = TFS.Projeto.Store.GetWorkItem(Configuracao.TFSConfig.WorkItem.Value);
                if (wi != null)
                {
                    //if (wi.State == "Em Teste")
                    if (wi.State == "Ativo")
                    {
                        wi.Attachments.Add(new Attachment(sFile, String.Format(@"Snapshot - Caso de Teste: {0:d3} - Item do Teste: {1:d3}", Configuracao.NumeroCaso, Configuracao.NumeroFoto)));
                        wi.Save();
                        nIcon.ShowBalloonTip(1000, "Foto de Caso de Teste", String.Format("Caso: {0:D3} - Teste: {1:D3}. {2} - Imagem salva no WorkItem {3}.", Configuracao.NumeroCaso, Configuracao.NumeroFoto, (char)13, wi.Id), ToolTipIcon.Info);
                    }
                }
            }
        }

        private void btnConfirmar_Click(object sender, EventArgs e)
        {
            Configuracao.Diretorio = txtDiretorio.Text;
            Configuracao.Prefixo = txtPrefixo.Text;
            Configuracao.IniciarAutomaticamente = chkIniciar.Checked;
            if (cmbWorkItem.SelectedValue != null)
                Configuracao.TFSConfig.WorkItem = (int)cmbWorkItem.SelectedValue;
            string sConfig = SerializeObject(Configuracao);
            StreamWriter sw = new StreamWriter(ArquivoConfig);
            sw.Write(sConfig);
            sw.Close();
            SetStartup(Application.ProductName, Configuracao.IniciarAutomaticamente);
            this.WindowState = FormWindowState.Minimized;
            this.Hide();
        }


        private void btnSelecionar_Click(object sender, EventArgs e)
        {
            if (dlgDiretorio.ShowDialog() == DialogResult.OK)
                txtDiretorio.Text = dlgDiretorio.SelectedPath;
        }

        private void frmSnapShot_Load(object sender, EventArgs e)
        {
            Configuracao = new SnapShot();            

            FileInfo fConfiguracao = new FileInfo(ArquivoConfig);

            if (fConfiguracao.Exists)
            {
                string sConfig;
                using (StreamReader sr = fConfiguracao.OpenText())
                {
                    sConfig = sr.ReadToEnd();
                }
                Configuracao = (SnapShot)DeserializeObject(sConfig, typeof(SnapShot));
            }
            else
            {
                Directory.CreateDirectory(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\SnapShot");
                this.WindowState = FormWindowState.Normal;
                this.Show();
            }
            MostraConfiguracao(true);
        }

        private void MostraConfiguracao(bool todos)
        {
            TFS.NomeServidor = Configuracao.TFSConfig.Servidor;
            pnlWI.Visible = Configuracao.TFSConfig.UsarTFS;
            if (pnlWI.Visible)
            {
                bntAtualizar_Click(null, null);
            }

            if (todos)
            {
                txtDiretorio.Text = Configuracao.Diretorio;
                txtPrefixo.Text = Configuracao.Prefixo;
                chkIniciar.Checked = Configuracao.IniciarAutomaticamente;
            }
            txtCaso.Text = Configuracao.NumeroCaso.ToString();
            txtTeste.Text = Configuracao.NumeroFoto.ToString();
        }

        public string SerializeObject(Object pObject)
        {
            try
            {
                String XmlizedString = null;
                MemoryStream memoryStream = new MemoryStream();
                XmlSerializer xs = new XmlSerializer(pObject.GetType());
                XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
                xs.Serialize(xmlTextWriter, pObject);
                memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
                XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());
                return XmlizedString;
                //return memoryStream.ToArray();
            }
            catch (Exception e)
            {
                System.Console.WriteLine(e);
                return null;
            }
        }

        public Object DeserializeObject(String pXmlizedString, Type type)
        {
            XmlSerializer xs = new XmlSerializer(type);
            MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(pXmlizedString));
            XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
            return xs.Deserialize(memoryStream);
        }

        private String UTF8ByteArrayToString(Byte[] characters)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            String constructedString = encoding.GetString(characters);
            return (constructedString);
        }

        private Byte[] StringToUTF8ByteArray(String pXmlString)
        {
            UTF8Encoding encoding = new UTF8Encoding();
            Byte[] byteArray = encoding.GetBytes(pXmlString);
            return byteArray;
        }

        private void btnReiniciar_Click(object sender, EventArgs e)
        {
            if (MessageBox.Show(String.Format("Atenção: Ao reiniciar, somente as fotos do caso {0:D3} serão apagadas.{1}Deseja realmente continuar?", Configuracao.NumeroCaso, (char)13), "Reiniciar", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
            {
                Configuracao.NumeroFoto = 0;
                string[] arquivos = Directory.GetFiles(Configuracao.Diretorio, String.Format(@"{0} - C{1:D3}T* - {2}.jpg", Configuracao.Prefixo, Configuracao.NumeroCaso, Environment.UserName));
                foreach (string arquivo in arquivos)
                {
                    FileInfo imgInfo = new FileInfo(arquivo);
                    imgInfo.Delete();
                }                
            }
            MostraConfiguracao(false);
        }

        private void btnCancelar_Click(object sender, EventArgs e)
        {
            MostraConfiguracao(true);
            this.WindowState = FormWindowState.Minimized;
            this.Hide();
        }

        private void SetStartup(string AppName, bool enable)
        {
            string runKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run";

            Microsoft.Win32.RegistryKey startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey);

            if (enable)
            {
                if (startupKey.GetValue(AppName) == null)
                {
                    startupKey.Close();
                    startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey, true);
                    // Add startup reg key
                    startupKey.SetValue(AppName, Application.ExecutablePath.ToString());
                    startupKey.Close();
                }
            }
            else
            {
                // remove startup
                startupKey = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(runKey, true);
                startupKey.DeleteValue(AppName, false);
                startupKey.Close();
            }
        }

        private void cmnConfigurar_Click(object sender, EventArgs e)
        {
            this.Show();
            this.WindowState = FormWindowState.Normal;
        }

        private void cmnSair_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void txtPrefixo_KeyPress(object sender, KeyPressEventArgs e)
        {
            string caracteresInvalidos = "\\'\"@!#$%¨&*()+=´`~^§ªº°,<>;:¹²³£¢¬";

            if (caracteresInvalidos.IndexOf(e.KeyChar) != -1)
            {
                e.Handled = true;
            }
        }

        private void frmSnapShot_FormClosing(object sender, FormClosingEventArgs e)
        {
            btnConfirmar_Click(null, null);
        }

        private void btnAvançar_Click(object sender, EventArgs e)
        {
            Configuracao.NumeroCaso++;
            Configuracao.NumeroFoto = 0;
            MostraConfiguracao(false);
            nIcon.ShowBalloonTip(1000, "Mudança de Caso de Teste (+)", String.Format("Caso: {0:D3}. Contagem de fotos reiniciada.", Configuracao.NumeroCaso), ToolTipIcon.Info); 
        }

        private void btnVoltar_Click(object sender, EventArgs e)
        {
            if (Configuracao.NumeroCaso > 1)
                Configuracao.NumeroCaso--;
            Configuracao.NumeroFoto = 0;
            MostraConfiguracao(false);
            nIcon.ShowBalloonTip(1000, "Mudança de Caso de Teste (-)", String.Format("Caso: {0:D3}. Contagem de fotos reiniciada.", Configuracao.NumeroCaso), ToolTipIcon.Info); 
        }

        private void btnTFS_Click(object sender, EventArgs e)
        {
            frmTFS form = new frmTFS();
            form.ConfigTFS = Configuracao.TFSConfig;
            if (form.ShowDialog() == DialogResult.OK)
            {
                pnlWI.Visible = Configuracao.TFSConfig.UsarTFS;
                bntAtualizar_Click(null, null);
            }
        }

        private Image CaptureAndSave()
        {
            uint intReturn = 0;
            NativeWIN32.INPUT structInput;
            structInput = new NativeWIN32.INPUT();
            structInput.type = (uint)1;
            structInput.ki.wScan = 0;
            structInput.ki.time = 0;
            structInput.ki.dwFlags = 0;
            structInput.ki.dwExtraInfo = 0;

            //Press Alt Key
            //structInput.ki.wVk = (ushort)NativeWIN32.VK.MENU;
            //intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));

            //Keyup Control
            structInput.ki.dwFlags = NativeWIN32.KEYEVENTF_KEYUP;
            structInput.ki.wVk = (ushort)NativeWIN32.VK.CONTROL;
            intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));

            
            // Key down the actual key-code
            structInput.ki.dwFlags = NativeWIN32.KEYEVENTF_KEYDOWN;
            structInput.ki.wVk = (ushort)NativeWIN32.VK.SNAPSHOT;//vk;
            intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));

            // Key up the actual key-code
            structInput.ki.dwFlags = NativeWIN32.KEYEVENTF_KEYUP;
            structInput.ki.wVk = (ushort)NativeWIN32.VK.SNAPSHOT;//vk;
            intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));

            //Keyup Alt
            //structInput.ki.dwFlags = NativeWIN32.KEYEVENTF_KEYUP;
            //structInput.ki.wVk = (ushort)NativeWIN32.VK.MENU;
            //intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));            

            //Keyup Control
            structInput.ki.dwFlags = NativeWIN32.KEYEVENTF_KEYDOWN;
            structInput.ki.wVk = (ushort)NativeWIN32.VK.CONTROL;
            intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));

            System.Threading.Thread.Sleep(100);
            IDataObject data = Clipboard.GetDataObject();

            if (data.GetDataPresent(DataFormats.Bitmap))
            {
                Image image = (Image)data.GetData(DataFormats.Bitmap, true);                

                //image.Save(@"C:\image" + ".bmp", System.Drawing.Imaging.ImageFormat.Bmp);
                //image.Save(@"C:\image" + ".jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
                //image.Save(@"C:\image" + ".gif", System.Drawing.Imaging.ImageFormat.Gif);
                return image;
            }
            else
            {
                Console.WriteLine("The Data In Clipboard is not in an image format");
                return null;
            }
        }

        public class NativeWIN32
        {
            public const ushort KEYEVENTF_KEYUP = 0x0002;
            public const ushort KEYEVENTF_KEYDOWN = 0x0;

            public enum VK : ushort
            {
                SHIFT = 0x10,
                CONTROL = 0x11,
                MENU = 0x12,
                ESCAPE = 0x1B,
                BACK = 0x08,
                TAB = 0x09,
                RETURN = 0x0D,
                PRIOR = 0x21,
                NEXT = 0x22,
                END = 0x23,
                HOME = 0x24,
                LEFT = 0x25,
                UP = 0x26,
                RIGHT = 0x27,
                DOWN = 0x28,
                SELECT = 0x29,
                PRINT = 0x2A,
                EXECUTE = 0x2B,
                SNAPSHOT = 0x2C,
                INSERT = 0x2D,
                DELETE = 0x2E,
                HELP = 0x2F,
                NUMPAD0 = 0x60,
                NUMPAD1 = 0x61,
                NUMPAD2 = 0x62,
                NUMPAD3 = 0x63,
                NUMPAD4 = 0x64,
                NUMPAD5 = 0x65,
                NUMPAD6 = 0x66,
                NUMPAD7 = 0x67,
                NUMPAD8 = 0x68,
                NUMPAD9 = 0x69,
                MULTIPLY = 0x6A,
                ADD = 0x6B,
                SEPARATOR = 0x6C,
                SUBTRACT = 0x6D,
                DECIMAL = 0x6E,
                DIVIDE = 0x6F,
                F1 = 0x70,
                F2 = 0x71,
                F3 = 0x72,
                F4 = 0x73,
                F5 = 0x74,
                F6 = 0x75,
                F7 = 0x76,
                F8 = 0x77,
                F9 = 0x78,
                F10 = 0x79,
                F11 = 0x7A,
                F12 = 0x7B,
                OEM_1 = 0xBA,   // ',:' for US
                OEM_PLUS = 0xBB,   // '+' any country
                OEM_COMMA = 0xBC,   // ',' any country
                OEM_MINUS = 0xBD,   // '-' any country
                OEM_PERIOD = 0xBE,   // '.' any country
                OEM_2 = 0xBF,   // '/?' for US
                OEM_3 = 0xC0,   // '`~' for US
                MEDIA_NEXT_TRACK = 0xB0,
                MEDIA_PREV_TRACK = 0xB1,
                MEDIA_STOP = 0xB2,
                MEDIA_PLAY_PAUSE = 0xB3,
                LWIN = 0x5B,
                RWIN = 0x5C
            }


            public struct KEYBDINPUT
            {
                public ushort wVk;
                public ushort wScan;
                public uint dwFlags;
                public long time;
                public uint dwExtraInfo;
            };

            [StructLayout(LayoutKind.Explicit, Size = 28)]
            public struct INPUT
            {
                [FieldOffset(0)]
                public uint type;
                [FieldOffset(4)]
                public KEYBDINPUT ki;
            };


            [DllImport("user32.dll")]
            public static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);

        }

        private void bntAtualizar_Click(object sender, EventArgs e)
        {
            List<WorkItemList> wl = TFS.ListaMeusWorkItens(Configuracao.TFSConfig.FiltroEstado);

            cmbWorkItem.DataSource = wl;
            cmbWorkItem.ValueMember = "Id";
            cmbWorkItem.DisplayMember = "Title";            
            
            cmbWorkItem.SelectedItem = wl.Find(delegate(WorkItemList w) { return w.Id == (Configuracao.TFSConfig.WorkItem == null ? w.Id : Configuracao.TFSConfig.WorkItem.Value); });
        }
    }
}
